 /**
  * typeof(null) -> object
  * origin.hasOwnProperty(key) -> true -> 非原型上的属性
  * Object.prototype.toString.call(key) -> 判断数据的类型 -> [object Array]:数组
  */

 function deepClone(origin, target) {
     var target = target || {},
         toStr = Object.prototype.toString,
         arrType = '[object Array]';
     for (var key in origin) {
         //过滤掉原型上的属性
         if (origin.hasOwnProperty(key)) {
             //判断要拷贝的值的类型是引用值还是原始值，还要排除null，因为typeof(null) -> object
             if ((typeof (origin[key]) === 'object') && origin[key] != null) {
                 //引用值，如果为引用值则声明一个空引用值（[]、{}）进行递归遍历，直到为原始值，就拷贝
                 if (toStr.call(origin[key]) === arrType) {
                     //数组
                     target[key] = [];
                 } else {
                     //对象
                     target[key] = {};
                 }
                 //如果遍历的key值为引用值，则继续递归、遍历，直到为原始值，然后就拷贝
                 deepClone(origin[key], target[key]);

             } else {
                 //原始值-> 原始值直接拷贝
                 target[key] = origin[key];
             }
         }
     }
     return target;
 }
 /**
  * 添加绑定事件-封装
  * @param {*} el  
  * @param {*} type -- 事件类型:click、scroll...
  * @param {*} fn   -- 函数
  * addEvent(oBtn, 'click', function () {
  *   console.log(2);
  * })
  */
 function addEvent(el, type, fn) {
     if (el.addEventListener) {
         //IE9以下不兼容，W3C规范 --> elem.addEventListener(事件类型,事件处理函数,false)
         el.addEventListener(type, fn, false);
     } else if (el.attachEvent) {
         // IE8及以下的绑定方法：elem.attachEvent(事件类型(on-xxx),事件处理函数)
         el.attachEvent('on' + type, function () {
             fn.call(el); //改变el.attachEvent()的this指向:window -> el
         });
     } else {
         el['on' + type] = fn; //el.onclick = fn; --> el[onclck] = fn
     }
 }

 // 清除绑定事件
 function removeEvent(elem, type, fn) {
     if (elem.addEventListener) {
         elem.removeEventListener(type, fn, false);
     } else if (elem.attachEvent) {
         elem.detachEvent('on' + type, fn);
     } else {
         elem['on' + type] = null;
     }
 }

 /**
  * 取消默认事件
  * 兼容性最好的是:return false;但是只能在句柄绑定里面去使用
  * W3C规范：e.preventDefault(); IE9不兼容e.preventDefault()
  * IE9以下使用：e.returnValue = false;
  */
 function preventDefaultEvent(e) {
     var e = e || window.event;
     if (e.preventDefault) {
         e.preventDefault();
     } else {
         e.returnValue = false;
     }
 }

 // 禁止冒泡事件-封装
 function cancelBubble(e) {
     /**
      * e:当前正在处理的事件对象
      * IE8:window.event
      */
     var e = e || window.event; //判断是否支持e，不支持就使用window.event
     if (e.stopPropagation) {
         e.stopPropagation();
     } else {
         e.cancelBubble = true;
     }
 }

 //获取元素的子元素节点方法-封装
 function elemChildren(node) {
     //将类数组转换成数组的方法：Array.prototype.slice.call(arr); 
     var temp = {
         'length': 0,
         'push': Array.prototype.push, //将数组的push方法挂在到对象上
         'splice': Array.prototype.splice //将数组的splice方法挂在到对象上，将类数组转换成数组
     }
     var len = node.childNodes.length;
     for (var i = 0; i < len; i++) {
         var childItem = node.childNodes[i];
         if (childItem.nodeType === 1) {
             temp.push(childItem);
         }
     }
     return temp;
 }

 //获取元素的父元素节点方法-封装
 function elemParent(node, n) {
     var type = typeof (n);

     if (type === 'undefined') {
         return node.parentNode;
     } else if (n <= 0 || type !== 'number') {
         return;
     }

     while (n) {
         node = node.parentNode;
         n--;
     }

     return node;
 }

 //获取元素的距离-封装
 function getElemDocPostion(el) {
     var parent = el.offestParent,
         offsetLeft = el.offsetLeft,
         offsetTop = el.offsetTop;
     while (parent) {
         offsetLeft += parent.offsetLeft;
         offsetTop += parent.offsetTop;
         parent += parent.offsetParent;
     }
     return {
         left: offsetLeft,
         top: offsetTop
     }
 }

 /**
  * 获取元素的属性值-兼容模式封装
  * 使用：getStyles(elem,'height')
  */
 function getStyles(elem, prop) {
     if (window.getComputedStyle) {
         if (prop) {
             // 等同于：window.getComputedStyle(elem, null).prop
             return window.getComputedStyle(elem, null)[prop];
         } else {
             return window.getComputedStyle(elem, null);
         }
     } else {
         //IE8以下
         if (prop) {
             return elem.currentStyle[prop];
         } else {
             return elem.currentStyle;
         }
     }
 }

 //查看滚动条的滚动距离-兼容模式封装
 function getScrollOffset() {
     if (window.pegeXOffset) {
         // 兼容window.pageXOffset/pageYOffset
         return {
             left: window.pageXOffset,
             top: window.pageYOffset
         }
     } else {
         /**
          * 支持document.documentElement.scrollLeft的，document.body.scrollLeft的值为0
          * 支持document.body.scrollLeft的，document.documentElement.scrollLeft的值为0
          * 所以，两者相加就是，能兼容其中一种
          */
         return {
             left: document.documentElement.scrollLeft + document.body.scrollLeft,
             top: document.documentElement.scrollLeft + document.body.scrollLeft
         }
     }
 }

 //浏览器可视区域的尺寸(窗口的宽高)-兼容模式封装
 function getViewPortSize() {
     if (window.innerWidth) {
         //兼容window.innerWidth/innerHeight
         return {
             width: window.innerWidth,
             height: window.innerHeight
         }
     } else {
         //IE9/IE8及以下
         if (document.compatMode === 'BackCompat') {
             //怪异模式
             return {
                 width: document.body.clinetWidth,
                 height: document.body.clinetHeight
             }
         } else {
             //标准模式
             return {
                 width: document.documentElement.clinetWidth,
                 height: document.documentElement.clinetHeight
             }
         }
     }
 }

 //文档（html页面）尺寸（宽度、高度）- 兼容模式封装
 function getScrollSize() {
     if (document.body.scrollWidth) {
         //W3C的规范
         return {
             width: document.body.scrollWidth,
             height: document.body.scrollHeight
         }
     } else {
         return {
             width: document.documentElment.scrollWidth,
             height: document.documentElement.scrollHeight
         }
     }
 }

 /**
  * 获取pageX/pageY-兼容模式封装
  * pageX/pageY:鼠标位置相对于当前文档的坐标（包含滚动条的距离）IE9以下不支持
  * getScrollOffset().left/top：滚动条的滚动距离-x/y轴
  * document.documentElement.clientLeft:浏览器的偏移值
  * clientX:鼠标位置相对于当前可视区域的坐标（不包括滚动条的距离）
  */
 function pagePos(e) {
     var sLeft = getScrollOffset().left,
         sTop = getScrollOffset().top,
         cLeft = document.documentElement.clientLeft || 0,
         cTop = document.documentElement.clientTop || 0;

     return {
         X: e.clientX + sLeft - cLeft,
         Y: e.clientY + sTop - cTop
     }
 }

 // 拖拽函数封装
 function elemDrag(elem) {
     var x,
         y;
     //鼠标按下
     addEvent(elem, 'mousedown', function (e) {
         var e = e || window.event;
         //鼠标位置相对于当前文档的坐标-元素到浏览器的距离 = 鼠标到元素边界的距离
         x = pagePos(e).X - getStyles(elem, 'left');
         y = pagePos(e).Y - getStyles(elem, 'top');

         addEvent(document, 'mousemove', mouseMove);
         addEvent(document, 'mouseup', mouseUp);
         cancelBubble(e); //禁止冒泡事件
         preventDefaultEvent(e); //取消默认事件
     });

     function mouseMove(e) {
         var e = e || window.event;
         /**
          * x ：不管怎么拖拽元素，始终不变的是鼠标到元素边界的距离
          * 用鼠标拖拽元素之后的位置相对于当前文档的坐标 - 鼠标到元素边界的距离
          *  = 用鼠标拖拽元素之后在浏览器的位置
          */
         elem.style.left = pagePos(e).X - x + 'px'; //设置元素x轴顶点的坐标
         elem.style.top = pagePos(e).Y - y + 'px'; //设置元素y轴顶点的坐标
     }

     //鼠标放开 
     function mouseUp(e) {
         var e = e || window.event;
         removeEvent(document, 'mousemove', mouseMove); //清除鼠标按下事件
         removeEvent(document, 'mouseup', mouseUp); //清除鼠标放开事件
     }
 }